package com.yongchun.pubInter;



import com.yongchun.commons.NumberUtil;
import com.yongchun.commons.SkList;
import com.yongchun.commons.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.repository.MongoRepository;

import java.lang.reflect.ParameterizedType;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;

/**
 * @author sunke
 * @version 1.0
 * @Description
 * @date 2022-08-30 23:11
 */
public abstract class BaseService<T extends BaseIdDoMain<KeyType>, TS extends BaseSearch, KeyType> {


    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 如果有关联就就重写这个方法
     * 关联表相关信息
     *
     * @return
     */
    public List<TableJoin> getTabelJoinList() {

        return null;
    }


    public Class<T> getDomainClass() {
        ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
        return (Class) type.getActualTypeArguments()[0];
    }

    public Class<TS> getSearchClass() {
        ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
        return (Class) type.getActualTypeArguments()[1];
    }

    public abstract MongoRepository<T, KeyType> getDao();


    /**
     * @param search
     * @return
     * @throws Exception
     */
    public long getListCount(TS search) throws SkException {


        List<AggregationOperation> operationList = SkList.getInstance();

        //添加关联表
        addTableAggregationOperation(operationList);

        /*  //添加搜索条件
         */
        operationList.add(Aggregation.match(search));

        operationList.add(Aggregation.count().as("count"));
        operationList.add(Aggregation.project("count"));

        AggregationResults<HashMap> results = mongoTemplate.
                aggregate(Aggregation.newAggregation(operationList), getDomainClass(), HashMap.class);

        if(results.getMappedResults().size()==0){
            return  0;
        }

        try {
            return NumberUtil.parseLong(results.getMappedResults().get(0).get("count"));
        } catch (Exception e) {
            e.printStackTrace();

        }
        return 0;


        //  search.with(search);
        //  return mongoTemplate.count(search, getDomainClass());


    }

/*
    private ProjectionOperation addTableFields(ProjectionOperation projectionOperation) {

        if (StringUtil.isNullOrEmpty(projectionOperation)) {
            return projectionOperation;
        }

        List<TableJoin> tableJoinList = getTabelJoinList();


        if (StringUtil.isNullOrEmpty(tableJoinList)) {

            return projectionOperation;
        }


        for (TableJoin item : tableJoinList) {


            List<String> showFieldList = item.getShowFields();
            if (StringUtil.isNullOrEmpty(showFieldList)) {
                continue;
            }


          *//*  for (String showField : showFieldList) {
                projectionOperation = projectionOperation.and(item.getAs() + "." + showField).as(item.getAs() + "." +showField);
            }*//*


        }

        return projectionOperation;


    }*/

    private void addTableAggregationOperation(List<AggregationOperation> operationList) {

        List<TableJoin> tableJoinList = getTabelJoinList();

        if (StringUtil.isNullOrEmpty(tableJoinList)) {

            return;
        }


        for (TableJoin item : tableJoinList) {
            operationList.add(Aggregation.lookup(item.getFrom(), item.getLocalField(), item.getForeignField(), item.getAs()));
            // operationList.add(Aggregation.unwind(item.getAs(),true));
        }


    }


    public List<T> getList(TS search) throws SkException {

        List<AggregationOperation> operationList = SkList.getInstance();

        if (StringUtil.isNotObjEmpty(search.getOrderBy())) {
            // 排序
            Sort.Direction direction = Sort.Direction.DESC;

            if ("asc".equalsIgnoreCase(search.getOrderDesc())) {
                direction = Sort.Direction.ASC;
            }


            operationList.add(Aggregation.sort(direction, search.getOrderBy()));
        }

        //添加关联表
        addTableAggregationOperation(operationList);
        //添加搜索条件
        operationList.add(Aggregation.match(search));


        ProjectionOperation projectionOperation = Aggregation.project(getDomainClass());
        List<TableJoin> tableJoinList = getTabelJoinList();
        if (StringUtil.isNotObjEmpty(tableJoinList)) {
            for (TableJoin tableJoin : tableJoinList) {
                if (StringUtil.isNullOrEmpty(tableJoin.getShowFieldList())) {
                    continue;
                }

                for (TableJoinShowField showField : tableJoin.getShowFieldList()) {

                    projectionOperation = projectionOperation.and(tableJoin.getAs() + "." + showField.getFieldName()).as(showField.getFieldAs());

                }


            }


        }


        operationList.add(projectionOperation);

        if (search.getPageSize() > 0) {
            //起始
            operationList.add(Aggregation.skip(Long.valueOf(search.getOffset())));
            //查询条数
            operationList.add(Aggregation.limit(search.getPageSize()));
        }

        AggregationOptions aggregationOptions=AggregationOptions.builder().allowDiskUse(true).build();
        Aggregation aggregation=Aggregation.newAggregation(operationList).withOptions(aggregationOptions);


        AggregationResults<T> results = mongoTemplate.
                aggregate(aggregation, getDomainClass(), getDomainClass());
        return results.getMappedResults();


    }


    /**
     * 分页
     *
     * @param search
     * @return
     */
    public PageResult<T> paginate(TS search) throws SkException {

        PageResult<T> pageResult = new PageResult<>();

        PageBean page = new PageBean();
        page.setTotalCount(getListCount(search));
        page.setPageSize(search.getPageSize());

        //说明显示全部
        if (search.getPageSize() == -1) {
            page.setPageSize(page.getTotalCount());
            search.setPageSize((int) page.getPageSize());
        }

        long totalPage = page.getTotalPage();
        long pageNumber = search.getPageNumber();
        if (pageNumber > totalPage) {
            pageNumber = totalPage;
        }
        page.setCurrentPage(pageNumber);
        search.setPageNumber((int) pageNumber);
        pageResult.setPageBean(page);

        if (page.getTotalCount() == 0) {
            return pageResult;
        }


        pageResult.setList(getList(search));


        return pageResult;

    }


    public T insert(T model) throws SkException {


        return getDao().insert(model);

    }


    public List<T> getAll(TS search) throws SkException {


        return getList(search);


        //    return mongoTemplate.find(search, getDomainClass());

    }


    public T getDetailBySearch(TS search) {
        if (search == null) {
            try {
                search = getSearchClass().newInstance();
            } catch (Exception e) {

            }
        }
        search.setPageSize(1);
        try {

           long num= getListCount(search);
           if(num==0){
               return null;
           }


            return getList(search).get(0);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 更新
     *
     * @param model
     * @return
     * @throws Exception
     */
    public T update(T model) throws SkException {

        return getDao().save(model);


    }


    /**
     * 删除
     *
     * @param id
     * @return
     * @throws Exception
     */
    public void delete(KeyType id) throws SkException {

        getDao().deleteById(id);

    }

    public T getDetail(KeyType id) throws SkException {

        Optional<T> optionalObj = getDao().findById(id);
        if (optionalObj.isPresent()) {
            return optionalObj.get();
        }
        return null;

    }


    public void batchDelete(List<KeyType> ids) throws SkException {

        try {
          /*  TS search = getSearchClass().newInstance();
            search.setIdIn(ids);*/

            if (StringUtil.isNullOrEmpty(ids)) {
                return;
            }
            for (KeyType id : ids) {
                delete(id);

            }


            //   mongoTemplate.findAllAndRemove(search, getDomainClass());

        } catch (Exception e) {

        }


    }


}
